package com.google.code.server4j.util;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public abstract class AbstractLifeCycle implements LifeCycle {

	private static final Object LOCK = new Object();
	protected final List<LifeCycleListener> listeners = new CopyOnWriteArrayList<LifeCycleListener>(); 
	protected static final int PRE_INIT = 1;
	protected static final int POST_INIT = 2;
	protected static final int PRE_START = 3;
	protected static final int POST_START = 4;
	protected static final int PRE_STOP = 5;
	protected static final int POST_STOP = 6;
	
	private int state = POST_STOP;
	
	@Override
	public final void init() {
		synchronized(LOCK) {
			try {
				if(state==PRE_INIT || state==POST_INIT) {
					return;
				}
				preInit();
				doInit();
				postInit();
			} catch(Exception e) {
				e.printStackTrace();
			} catch(Throwable ex) {
				ex.printStackTrace();
			}
		}
	}

	private void preInit() {
		state = PRE_INIT;
		Log.debug("pre init "+this);
		for(LifeCycleListener listener:listeners) {
			listener.lifeCyclePreInit();
		}
	}
	
	private void postInit() {
		state = POST_INIT;
		Log.debug("post init "+this);
		for(LifeCycleListener listener:listeners) {
			listener.LifeCyclePostInit();
		}
	}
	
	protected abstract void doInit()throws Exception;
	
	@Override
	public void start() {
		synchronized(LOCK) {
			try {
				if(state==PRE_START || state==POST_START) {
					return;
				}
				preStart();
				doStart();
				postStart();
			} catch(Exception e) {
				e.printStackTrace();
			} catch(Throwable ex) {
				ex.printStackTrace();
			}
		}
	}
	
	private void preStart() {
		state = PRE_START;
		Log.debug("pre start "+this);
		for(LifeCycleListener listener:listeners) {
			listener.lifeCyclePreStart();
		}
	}
	
	private void postStart() {
		state = POST_START;
		Log.debug("post start "+this);
		for(LifeCycleListener listener:listeners) {
			listener.lifeCyclePostStart();
		}
	}
	
	protected abstract void doStart()throws Exception;
	
	
	@Override
	public void stop() {
		synchronized(LOCK) {
			try {
				if(state==PRE_STOP || state==POST_STOP) {
					return;
				}
				preStop();
				doStop();
				postStop();
			} catch(Exception e) {
				e.printStackTrace();
			} catch(Throwable ex) {
				ex.printStackTrace();
			}
		}		
	}

	private void preStop() {
		state = PRE_STOP;
		Log.debug("pre stop "+this);
		for(LifeCycleListener listener:listeners) {
			listener.lifeCyclePreStop();
		}
	}
	
	private void postStop() {
		state = POST_STOP;
		Log.debug("post stop "+this);
		for(LifeCycleListener listener:listeners) {
			listener.lifeCyclePostStop();
		}
	}
	
	protected abstract void doStop()throws Exception;
	
	@Override
	public void addLifeCycleListener(LifeCycleListener listener) {
		listeners.add(listener);
		
	}

	@Override
	public void removeLifeCycleListener(LifeCycleListener listener) {
		listeners.remove(listener);
		
	}

}
